type Node     native;  // *vdom.Node
type Styles   native;  // *vdom.Styles
type Attrs    native;  // *vdom.Attrs
type Events   native;  // *vdom.Events
type Content  native;  // vdom.Content

type Tag String;


/// Be careful! This is technically NOT a pure function.
/// The vDOM driver in `webui.js` uses the memory address of a vNode as an ID.
/// Therefore, a vNode cannot be used more than once.
/// In addition, due to some restrictions, a vNode cannot move across subtrees.
///
function Node:
    &(Tag) => Node
    native 'ui-dom-node';

function Node:
    &(Tag, String) => Node
    &(tag, text) =>
        { Node tag }
            . { with { Content text } };

function Node:
    &(Tag, List[Node]) => Node
    &(tag, children) =>
        { Node tag }
            . { with { Content children } };

function Node:
    &(Tag, Computed[List[Node]]) => Computed[Node]
    &(tag, @children) =>
        (@children map &(children) => { Node (tag, children) });

function Node:
    &(Tag, List[Computed[Node]]) => Computed[Node]
    &(tag, sources) =>
        { Node (tag, {combine(sources)}) };


function Styles:
    &(Map[String,String]) => Styles
    native 'ui-dom-styles';

function Styles:
    &(List[(String,String)]) => Styles
    &(styles) => { Styles { Map styles } };

function with:
    &(Node, Styles) => Node
    native 'ui-with-styles';


function Attrs:
    &(Map[String,String]) => Attrs
    native 'ui-dom-attrs';

function Attrs:
    &(List[(String,String)]) => Attrs
    &(attrs) => { Attrs { Map attrs } };

function with:
    &(Node, Attrs) => Node
    native 'ui-with-attrs';


function Events:
    &(Map[String,EventHandler]) => Events
    native 'ui-dom-events';

function Events:
    &(List[(String,EventHandler)]) => Events
    &(events) => { Events  { Map events } };

function with:
    &(Node, Events) => Node
    native 'ui-with-events';


function Content:
    &(String) => Content
    native 'ui-dom-text';

function Content:
    &(List[Node]) => Content
    native 'ui-dom-children';

function with:
    &(Node, Content) => Node
    native 'ui-with-content';

